<template>
	<div :class="getClass" ref="wrapperRef">
		<PageHeader :ghost="ghost" :title="title" v-bind="omit($attrs, 'class')" ref="headerRef" v-if="getShowHeader">
			<template #default>
				<template v-if="content">
					{{ content }}
				</template>
				<slot name="headerContent" v-else></slot>
			</template>
			<template #[item]="data" v-for="item in getHeaderSlots">
				<slot :name="item" v-bind="data || {}"></slot>
			</template>
		</PageHeader>

		<div class="overflow-hidden" :class="getContentClass" :style="getContentStyle" ref="contentRef">
			<slot></slot>
		</div>

		<PageFooter v-if="getShowFooter" ref="footerRef">
			<template #left>
				<slot name="leftFooter"></slot>
			</template>
			<template #right>
				<slot name="rightFooter"></slot>
			</template>
		</PageFooter>
	</div>
</template>
<script lang="ts">
import { CSSProperties, PropType, provide } from 'vue';

import { defineComponent, computed, watch, ref, unref } from 'vue';
import PageFooter from './PageFooter.vue';

import { useDesign } from '@/hooks/web/useDesign';
import { propTypes } from '@/utils/propTypes';
import { omit } from 'lodash-es';
import { PageHeader } from 'ant-design-vue';
import { useContentHeight } from '@/hooks/web/useContentHeight';
import { PageWrapperFixedHeightKey } from '..';
import { isString } from '@/utils/is';
// import { isArray } from '@/utils/is';

export default defineComponent({
	name: 'PageWrapper',
	components: { PageFooter, PageHeader },
	inheritAttrs: false,
	props: {
		// 页面标题
		title: propTypes.string,
		// pageHeader 的类型，将会改变背景颜色
		ghost: propTypes.bool,
		// 内容，位于title下方，与slots?.headerContent互斥
		content: propTypes.string,
		// 内容的css样式
		contentStyle: {
			type: Object as PropType<CSSProperties>,
		},
		// 内容背景色 默认白色：#151515
		contentBackground: propTypes.bool,
		// 内容是否撑满全屏，即使是高度不够的情况
		contentFullHeight: propTypes.bool,
		// 内容class
		contentClass: propTypes.oneOfType([propTypes.arrayOf(propTypes.string), propTypes.string]).def(''),
		// 是否固定高度？配合contentFullHeight可限制最大高度，避免出现滚动条
		fixedHeight: propTypes.bool,
		// 向上递归减去空闲空间的层级
		upwardSpace: propTypes.oneOfType([propTypes.number, propTypes.string]).def(0),
	},
	setup(props, { slots, attrs }) {
		const wrapperRef = ref(null);
		const headerRef = ref(null);
		const contentRef = ref(null);
		const footerRef = ref(null);
		const { prefixCls } = useDesign('page-wrapper');

		provide(
			PageWrapperFixedHeightKey,
			computed(() => props.fixedHeight),
		);

		const getIsContentFullHeight = computed(() => {
			return props.contentFullHeight;
		});

		const getUpwardSpace = computed(() => props.upwardSpace);
		const { redoHeight, setCompensation, contentHeight } = useContentHeight(
			getIsContentFullHeight,
			wrapperRef,
			[headerRef, footerRef],
			[contentRef],
			getUpwardSpace,
			ref(0.1),
		);
		setCompensation({ useLayoutFooter: true, elements: [footerRef] });

		const getClass = computed(() => {
			return [prefixCls, attrs.class ?? {}];
		});

		const getShowHeader = computed(
			() => props.content || slots?.headerContent || props.title || getHeaderSlots.value.length,
		);

		const getShowFooter = computed(() => slots?.leftFooter || slots?.rightFooter);

		const getHeaderSlots = computed(() => {
			return Object.keys(omit(slots, 'default', 'leftFooter', 'rightFooter', 'headerContent'));
		});

		const getContentStyle = computed((): CSSProperties => {
			const { contentFullHeight, contentStyle, fixedHeight } = props;
			if (!contentFullHeight) {
				return { ...contentStyle };
			}

			const height = `${unref(contentHeight)}px`;
			return {
				...contentStyle,
				minHeight: height,
				...(fixedHeight ? { height } : {}),
			};
		});

		const getContentClass = computed(() => {
			const { contentBackground, contentClass } = props;
			if (isString(contentClass)) {
				return [
					`${prefixCls}-content`,
					contentClass,
					{
						[`${prefixCls}-content-bg`]: contentBackground,
					},
				];
			}
			return [
				`${prefixCls}-content`,
				{
					[`${prefixCls}-content-bg`]: contentBackground,
				},
			].concat(contentClass);
		});

		watch(
			() => [getShowFooter.value],
			() => {
				redoHeight();
			},
			{
				flush: 'post',
				immediate: true,
			},
		);

		return {
			getContentStyle,
			wrapperRef,
			headerRef,
			contentRef,
			footerRef,
			getClass,
			getHeaderSlots,
			prefixCls,
			getShowHeader,
			getShowFooter,
			omit,
			getContentClass,
		};
	},
});
</script>
<style lang="less">
@prefix-cls: ~'@{namespace}-page-wrapper';

.@{prefix-cls} {
	position: relative;
	padding: 24px;
	background-color: #fff;

	.@{prefix-cls}-content {
		margin: 0;
	}

	.ant-page-header {
		padding-top: 0;
		padding-left: 0;
		&:empty {
			padding: 0;
		}
	}

	&-content-bg {
		background-color: @component-background;
	}
}
</style>
